/**************************************************************************
              TMere.c
*************************************************************************/

//---------- Réalisation de la tâche TMere---

/////////////////////////////////////////////////////////////////  INCLUDE
//-------------------------------------------------------- Include système
#include <sys/sem.h>// semaphore
#include <sys/shm.h>//memoire partagee
#include <sys/msg.h>// boite aux lettres
#include <sys/types.h>//waitpid  fork
#include <sys/wait.h>// waitpid
#include <sys/signal.h>
#include <unistd.h>// sleep
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

//------------------------------------------------------ Include personnel
#include "config.h"
#include "TMere.h"
#include "Simu.h"
#include "TLog.h"
#include "decision.h"
#include "Regle.h"
#include "TClavier.h"
#include "Simu.h"
#include "Monitoring.h"

//TODO include monitoring regle

///////////////////////////////////////////////////////////////////  PRIVE
//------------------------------------------------------------- Constantes
#define DROITS 0660
#define NB 1  //nb de semaphores elementaires
#define TEMPO_MERE 1
//------------------------------------------------------------------ Types

//---------------------------------------------------- Variables statiques
static pid_t pidMonitoring;
static pid_t pidLog;
static pid_t pidRegle;
static pid_t pidClavier;

static 	Regle * tabReg;

static int bal_historique; //message mere-> TLog
//------------------------------------------------------ Fonctions privées

//////////////////////////////////////////////////////////////////  PUBLIC
//---------------------------------------------------- Fonctions publiques

/****************************************************************************
 * fonction de test  TODO : a enlever après la simulation
*****************************************************************************/
void afficherCapteurs()
{
	int i;
	for(i=0;i<nbCapteur;i++)
	{
		printf("id capteur in table : %s\n",pTabCapteur[i].idCapteur);
	}
}

void afficherRegles()
{
	int i;
	for(i=0;i<nbRegle;i++)
	{
		printf("id actionneur in table : %s\n",tabReg[i].idActionneur);
	}
}
void remplirTabEnDur()
{
	MapCapteur capteur1;
	MapCapteur capteur2;
	MapCapteur capteur3;


	tabReg = pTabRegle;

	capteur1.idCapteur="T10100";
	pTabCapteur[0]=capteur1;

	capteur2.idCapteur="T20100";
	pTabCapteur[1]=capteur2;

	capteur3.idCapteur="T30100";
	pTabCapteur[2]=capteur3;


	nbCapteur=3;

	//afficherCapteurs();


	Regle * r1;
	Condition * c1;
	r1=(Regle *)malloc(sizeof(Regle));
	c1=(Condition *)malloc(sizeof(Condition));

	strcpy(c1->idCapteur , "T10100");
	c1->valMin = 0;
	c1->valMax = 30;
	r1->nbCondition = 1;
	strcpy(r1->idActionneur, "A20000");
	r1->onOff = 1;
	r1->valeur = 0.5;
	r1->tabCondition[0]=*c1;
	pTabRegle[0]=*r1;

	Regle * r2;
	Condition * c2;
	r2=(Regle *)malloc(sizeof(Regle));
	c2=(Condition *)malloc(sizeof(Condition));

	strcpy(c2->idCapteur , "T10100");
	c2->valMin = 5;
	c2->valMax = 90;
	r2->nbCondition = 1;
	strcpy(r2->idActionneur, "A20000");
	r2->onOff = 1;
	r2->valeur = 0.5;
	r2->tabCondition[0]=*c2;
	pTabRegle[1]=*r2;
	nbRegle=2;
	

	//afficherRegles();

	MapActionneur actionner;
	actionner.idActionneur="A10000";
	pTabActionneur[0]=actionner;
	actionner.idActionneur="A20000";
	pTabActionneur[1]=actionner;
	nbActionneur=2;


}


/****************************************************************************
 * fonctions utiles
*****************************************************************************/

void modifierTabCapteur(MsgCapteur * cap)
{
	int i;
	for(i=0;i<nbCapteur;i++)
	{
		if(strcmp(pTabCapteur[i].idCapteur,cap->idCapteur)==0)
		{
			pTabCapteur[i].valeur=cap->valeur;
			printf("##########capteur id %s modifie.\n",cap->idCapteur);
		}
	}
}

void modifierTabActionneur(MsgActionneur * act)
{
	int i;
	for(i=0;i<nbActionneur;i++)
	{
		if(strcmp(pTabActionneur[i].idActionneur,act->idActionneur)==0)
		{
			//TODO
			printf("##########Actionneur id %s modifie.\n",act->idActionneur);
		}
	}
}


void modifierValCapteur(MsgCapteur * msgCapteur)
{
	time_t t;
	time(&t);
	MsgHistorique msgs_h;
	MsgActionneur msg_a;

	//TODO acces BD

	//modifier la table
	modifierTabCapteur(msgCapteur);

	//envoyer un msg à la tache historique
	msgs_h.type=1;
	//TODO if(msgCapteur->typeMessage==2)
	sprintf(msgs_h.mtext,"Info : Modification valeur capteur. %s  capteur id : %s, valeur : %f \n",
			ctime(&t),msgCapteur->idCapteur,msgCapteur->valeur);
	if (msgsnd(bal_historique,(void *)&msgs_h,(sizeof(MsgHistorique)-sizeof(long)),IPC_NOWAIT) < 0 )
	{
		perror ("ModifierValCapteur :msgsnd error");
		exit(EXIT_FAILURE);
	}
	else
	{
			printf("ModifierValCapteur:historique sent.%s\n",msgs_h.mtext);
	}

	//envoyer le msg à la tache regle
	if (msgsnd(msgQCapteurUpdate,(void *)msgCapteur,(sizeof(MsgCapteur)-sizeof(long)),IPC_NOWAIT) < 0 )
	{
		perror ("ModifierValCapteur :msgsnd error");
		exit(EXIT_FAILURE);
	}
	else
	{
			printf("ModifierValCapteur:msg sent to TRegle.\n");
	}
	//envoyer à la tache monitoring
	msg_a.type=1;
	msg_a.onOff=msgCapteur->valeur-1;
	if (msgsnd(bal_mere_actionneur,&msg_a,(sizeof(MsgActionneur)-sizeof(long)),IPC_NOWAIT) < 0 )
	{
		perror ("ModifierValCapteur :msgsnd error");
		exit(EXIT_FAILURE);
	}
	else
	{
			printf("ModifierValCapteur:msg sent to TMonitoring.\n");
	}


}

void modifierValActionneur(MsgActionneur * msgAct)
{
	time_t t;
	time(&t);
	MsgHistorique msgs_h;

	//TODO acces BD

	//TODO modifier la table ?
	modifierTabActionneur(msgAct);

	//envoyer un msg à la tache historique
	msgs_h.type=1;
	//TODO if(msgCapteur->typeMessage==2)
	sprintf(msgs_h.mtext,"Info : Modification etat actionneur. %s  actionneur id : %s, valeur : %f \n",
			ctime(&t),msgAct->idActionneur,msgAct->valeur);
	if (msgsnd(bal_historique,(void *)&msgs_h,(sizeof(MsgHistorique)-sizeof(long)),IPC_NOWAIT) < 0 )
	{
		perror ("ModifierValActionneur :msgsnd error");
		exit(EXIT_FAILURE);
	}
	else
	{
			printf("ModifierValActionneur:historique sent.%s\n",msgs_h.mtext);
	}

	//envoyer le msg à la tache monitor
	if (msgsnd(bal_commande_actionneur,(void *)msgAct,(sizeof(MsgActionneur)-sizeof(long)),IPC_NOWAIT) < 0 )
	{
		perror ("ModifierValActionneur :msgsnd error");
		exit(EXIT_FAILURE);
	}
	else
	{
		printf("ModifierValActionneur:msg sent to TMonitoring.\n");
	}

}
/****************************************************************************
 * phase init de la tache mere
*****************************************************************************/
void InitMere()
{
	printf("InitMere :start\n");

	//creation semaphore
	semTabCapteur = semget(IPC_PRIVATE, NB, IPC_CREAT | DROITS);
	//initialisation du semaphore a 1
	semctl(semTabCapteur,0, SETVAL, 1);

	semTabActionneur = semget(IPC_PRIVATE, NB, IPC_CREAT | DROITS);
	semctl(semTabActionneur,0, SETVAL, 1);

	semTabRegle = semget(IPC_PRIVATE, NB, IPC_CREAT | DROITS);
	semctl(semTabRegle,0, SETVAL, 1);


	//creation des memoires partagees
	memTabCapteurId = shmget(IPC_PRIVATE,TAILLE_TAB_CAPTEUR,IPC_CREAT | DROITS);
	pTabCapteur=(MapCapteur *)shmat(memTabCapteurId, NULL,0);

	memTabActionneurId = shmget(IPC_PRIVATE,TAILLE_TAB_ACTIONNEUR,IPC_CREAT | DROITS);
	pTabActionneur=(MapActionneur *)shmat(memTabActionneurId, NULL,0);

	memTabRegleId = shmget(IPC_PRIVATE,TAILLE_TAB_REGLE,IPC_CREAT | DROITS);
	pTabRegle=(Regle *)shmat(memTabRegleId, NULL,0);

	//initialisation de la memoire partagee TabCapteur
	//TODO : acces à BD
	remplirTabEnDur();

	//creation des bals
	bal_monitoring_mere=msgget(IPC_PRIVATE, IPC_CREAT | DROITS);
	if(bal_monitoring_mere<0)
	{
		perror("msgget failed");
		return;
	 }

	bal_mere_actionneur=msgget(IPC_PRIVATE, IPC_CREAT | DROITS);
	if(bal_mere_actionneur<0)
	{
		perror("msgget failed");
		return;
	 }
	bal_commande_actionneur=msgget(IPC_PRIVATE, IPC_CREAT | DROITS);
	if(bal_commande_actionneur<0)
	{
		perror("msgget failed");
		return;
	 }
	msgQCapteurUpdate=msgget(IPC_PRIVATE, IPC_CREAT | DROITS);
	if(msgQCapteurUpdate<0)
	{
		perror("msgget failed");
		return;
	 }
	bal_historique=msgget(IPC_PRIVATE, IPC_CREAT | DROITS);
	if(bal_historique<0)
	{
		perror("msgget failed");
		return;
	 }

	printf("InitMere :end\n");
}
/****************************************************************************
 * phase moteur de la tache mere
*****************************************************************************/
//handler : gestion de la fin du moteurMere
void finMoteurMere(int noSignal)
{
	if(noSignal==SIGUSR1)
	{
		printf("******SIGUSR1 received,end of application*****\n"
				"**********************************************\n");
		DestMere();
	}
}
void MoteurMere()
{
	int run;
	MsgCapteur msg_capt_r;
	MsgActionneur msg_act_r;
	int lengthMsg_capt_r;
	int lengthMsg_act_r;
	int result_capt_r;
	int result_act_r;
	lengthMsg_capt_r=sizeof(MsgCapteur)-sizeof(long);
	lengthMsg_act_r=sizeof(MsgActionneur)-sizeof(long);
	run=1;
	printf("MoteurM :start\n");

	//a la reception du SIGUSER1, gestion de fin
	struct sigaction action;
	action.sa_handler=finMoteurMere;
	sigemptyset(&action.sa_mask);
	action.sa_flags=0;
	sigaction(SIGUSR1,&action,NULL);

	while(run)
	{
		//printf("MoteurM :motor\n");

		//recevoir le msg de type MsgCapteur en provenance de monitoring
		result_capt_r= msgrcv(bal_monitoring_mere, (void *) &msg_capt_r,lengthMsg_capt_r,0, MSG_NOERROR | IPC_NOWAIT);
		if(result_capt_r<lengthMsg_capt_r)
		{
			//perror ("MoteurM :msgrcv pb for bal_monitoring_mere");
		}
		else
		{
			printf("MoteurM :msg received from monitoring:\n"
					"capteur id %s,typeMsg %d,valeur %f\n"
					,msg_capt_r.idCapteur,msg_capt_r.typeMessage,msg_capt_r.valeur);

			//maj les valeurs & envoyer le msg à la tache regle
			modifierValCapteur(&msg_capt_r);
		}

		//recevoir le msg de typeMsgCapteur en provenance de regle
		result_act_r= msgrcv(bal_commande_actionneur, (void *) &msg_act_r,lengthMsg_act_r,0, MSG_NOERROR | IPC_NOWAIT);
		if(result_act_r<lengthMsg_act_r)
		{
			//perror ("MoteurM :msgrcv pb for bal_commande_actionneur");
		}
		else
		{
			printf("MoteurM :msg received from tacheRegle:\n"
					"actionneur id :%s,on-off :%d,valeur :%f\n"
					,msg_act_r.idActionneur,msg_act_r.onOff,msg_act_r.valeur);

			//maj les valeurs & envoyer le msg à la tache regle
			modifierValActionneur(&msg_act_r);
		}

		sleep(TEMPO_MERE);
	}
	printf("MoteurM :end\n");
}
/****************************************************************************
 * phase fin de la tache mere
*****************************************************************************/
void DestMere()
{
	MsgCapteur msg_c;
	MsgHistorique msg_h;
	MsgActionneur msg_a;
	int len_msg_h;
	int len_msg_c;
	int len_msg_a;
	len_msg_h=sizeof(MsgHistorique)-sizeof(long);
	len_msg_c=sizeof(MsgCapteur)-sizeof(long);
	len_msg_a=sizeof(MsgActionneur)-sizeof(long);

	printf("DestMere:start\n");

	/*
	//envoyer msg de type==4 pour signaler la fin à la tache monitoring
	msg_a.type=4;
	if(msgsnd(bal_mere_actionneur,(void *)&msg_a,len_msg_a,IPC_NOWAIT)<0)
	{
		perror ("msgsnd error for bal_mere_actionneur");
		exit(EXIT_FAILURE);
	}
	else
	{
		printf("DestMere:fin sent to TMonitoring.\n");
	}*/


	//envoyer msg de type==4 pour signaler la fin à la tache regle
	msg_c.type=4;
	if(msgsnd(msgQCapteurUpdate,(void *)&msg_c,len_msg_c,IPC_NOWAIT)<0)
	{
		perror ("msgsnd error for msgQCapteurUpdate");
		exit(EXIT_FAILURE);
	}
	else
	{
		printf("DestMere:fin sent to TRegle.\n");
	}

	//envoyer msg de type==4 pour signaler la fin à la tache log
	msg_h.type=4;
	strcpy(msg_h.mtext,"fin d application\n");
	if (msgsnd(bal_historique,(void *)&msg_h,len_msg_h,IPC_NOWAIT) < 0 )
	{
		perror ("msgsnd error for bal_historique");
		exit(EXIT_FAILURE);
	}
	else
	{
		printf("DestMere:fin sent to TLog.\n");
	}


	kill(pidMonitoring, SIGKILL);  //TODO a modifier

	waitpid(pidMonitoring, NULL, 0);

	//printf("DestMere:before pidLog\n");

	waitpid(pidLog, NULL, 0);

	//printf("DestMere:before pidRegle\n");
	waitpid(pidRegle, NULL, 0);

	//destruction des ressources
	semctl(semTabCapteur, 0, IPC_RMID, 0);
	semctl(semTabActionneur, 0, IPC_RMID, 0);
	semctl(semTabRegle, 0, IPC_RMID, 0);
	msgctl(bal_monitoring_mere, IPC_RMID, 0);
	msgctl(bal_mere_actionneur, IPC_RMID, 0);
	msgctl(bal_commande_actionneur, IPC_RMID, 0);
	msgctl(msgQCapteurUpdate, IPC_RMID, 0);
	msgctl(bal_historique, IPC_RMID, 0);
	shmctl(memTabActionneurId, IPC_RMID, 0);
	shmctl(memTabCapteurId, IPC_RMID, 0);
	shmctl(memTabRegleId, IPC_RMID, 0);

	printf("DestMere :************************************** end\n");
	exit(0);
}

/****************************************************************************
 * main
*****************************************************************************/
int main()
{
	int pidMere=getpid();

	InitMere();

	//creation des taches

	if((pidMonitoring=fork())==0)
	{
		TMonitoring();

	}
	else if((pidRegle = fork()) == 0)
	{
		TRegle();
	}
	else if((pidLog = fork()) == 0)
	{
		TLog(bal_historique);
	}
	else if((pidClavier=fork())==0)
	{
		TClavier(pidMere);
	}
	else
	{
		//dans mere
		printf("***************id du tache mere : %d,%d *******************\n",getpid(),pidMere);
		MoteurMere();

	}

	return 0;
}

